package com.zdkj.subway.st.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.util.DateUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.zdkj.common.core.util.R;
import com.zdkj.common.security.service.PigxUser;
import com.zdkj.common.security.util.SecurityUtils;
import com.zdkj.subway.st.constant.enums.StockEnum;
import com.zdkj.subway.st.dto.in.SwInputExportExcelDTO;
import com.zdkj.subway.st.dto.in.SysDictItemDTO;
import com.zdkj.subway.st.dvo.SwPmTicketAreaDvo;
import com.zdkj.subway.st.dvo.SwPmTicketCardTypeDvo;
import com.zdkj.subway.st.dvo.SwPmTicketCardTypeParamDvo;
import com.zdkj.subway.st.dvo.SwStInputDetailExcelDvo;
import com.zdkj.subway.st.entity.SwStInputDetail;
import com.zdkj.subway.st.entity.SwStStockDayCheckDetail;
import com.zdkj.subway.st.fegin.SubwaySupportService;
import com.zdkj.subway.st.mapper.SwStInputDetailMapper;
import com.zdkj.subway.st.mapper.SwStStockDayCheckDetailMapper;
import com.zdkj.subway.st.service.SwStInputDetailService;
import com.zdkj.subway.st.util.GenSerialNo;
import com.zdkj.subway.st.util.LocalDateConverter;
import com.zdkj.subway.st.util.LocalDateTimeConverter;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URLEncoder;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @ProjectName: zdkj
 * @Package: com.zdkj.subway.st.service.impl
 * @ClassName: SwStOutputDetailServiceImpl
 * @Description:
 * @Author: kangjian
 * @CreateDate: 2020/1/11 9:03
 * @Version: 1.0
 */
@Service
@AllArgsConstructor
@Slf4j
public class SwStInputDetailServiceImpl extends ServiceImpl<SwStInputDetailMapper, SwStInputDetail> implements SwStInputDetailService {

    @Autowired
    private SwStStockDayCheckDetailServiceImpl sdcd;

    @Autowired
    private GenSerialNo genSerialNo;

    @Autowired
    private SubwaySupportService subwaySupportService;

    @Resource
    private SwStStockDayCheckDetailMapper stStockDayCheckDetailMapper;

    @Override
    public boolean applyedBatch(List<Integer> ids) {
        Collection<SwStInputDetail> swStInputDetail = listByIds(ids);
        for (SwStInputDetail item : swStInputDetail) {
            if("1".equals(item.getCheckApproveStatus())||
                    "4".equals(item.getCheckApproveStatus())){
                item.setCheckApproveStatus("2");
            }
        }
        return updateBatchById(swStInputDetail);
    }
    @Override
    public boolean approvedBatch(List<Integer> ids) {
        Collection<SwStInputDetail> swStInputDetail = listByIds(ids);
        for (SwStInputDetail item : swStInputDetail) {
            if("2".equals(item.getCheckApproveStatus())){
                item.setCheckApproveStatus("3");
            }
        }
        return updateBatchById(swStInputDetail);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(SwStInputDetail swStInputDetail) {
        boolean issuccuess = true;
        //首先更新库存账
        SwStStockDayCheckDetail swStStockDayCheckDetail = new SwStStockDayCheckDetail();
        try {
            ////统计最新库存量 如果尚未尚未出库过，则库存为入库数
            //int settleNum = this.getSettleNum(swStInputDetail);
            //根据车票名称和库区，找到最大的id号对应的结存数量
            int settleNum = sdcd.getNewSettleNum(swStInputDetail.getTicketName(), swStInputDetail.getStockArea());
            String inputstorage = "入库";
            setSwStStockDayCheckDetail(swStStockDayCheckDetail,swStInputDetail,inputstorage);
            //更新库存量
            swStStockDayCheckDetail.setStorageNumber(swStInputDetail.getTicketNumber());
            //结存数量+入库数量 = 新的结存数量。
            swStStockDayCheckDetail.setSettleNumber(settleNum + swStInputDetail.getTicketNumber());
            issuccuess = sdcd.save(swStStockDayCheckDetail);

            if (!issuccuess) {
                issuccuess = false;
                throw new RuntimeException("库存更新异常！");
            }
            //设置关联库存id
            swStInputDetail.setStockdayid(swStStockDayCheckDetail.getId());
            //入库生成单号和更新基础表信息
            inputGenerateSingle(swStInputDetail);
            issuccuess = issuccuess && super.save(swStInputDetail);
            QueryWrapper<SwStStockDayCheckDetail> wrapper = new QueryWrapper<>();
            wrapper.lambda().eq(SwStStockDayCheckDetail::getId,swStInputDetail.getStockdayid());
            SwStStockDayCheckDetail stockDayCheckDetail = new SwStStockDayCheckDetail();
            stockDayCheckDetail.setOutputOrInputStockid(swStInputDetail.getId());
            stockDayCheckDetail.setOutputOrInputStockno(swStInputDetail.getInstockno());
            if (!StringUtils.isEmpty(swStInputDetail.getRemark())) {
                stockDayCheckDetail.setRemark(swStInputDetail.getRemark());
            }
            sdcd.update(stockDayCheckDetail,wrapper);
        } catch (Exception e) {
            log.error("", e);
            throw new RuntimeException(e);
        }
        return issuccuess ;
    }

    /**
     * 入库生成单号和更新基础表信息
     * @param swStInputDetail
     */
    public void inputGenerateSingle(SwStInputDetail swStInputDetail) {
        //其次更新入库基础表
        PigxUser user = SecurityUtils.getUser();
        swStInputDetail.setCreatorName(user.getUsername());
        swStInputDetail.setCreatorId(user.getId());
        //未分解
        swStInputDetail.setBreakFlag("0");
        //其他关联方式入库，不需要重新设置流水号
        if (StringUtils.isEmpty(swStInputDetail.getInstockno())) {
            //根据票种生成单号前缀
            String prefix = genSerialNo.getPreFixByTicketType(swStInputDetail.getTicketType());
            String serialno = genSerialNo.genSerioNo(StockEnum.StockType.INSTOCK.getValue());
            swStInputDetail.setInstockno(prefix+serialno);
        }
    }

    private void setSwStStockDayCheckDetail(SwStStockDayCheckDetail swStStockDayCheckDetail,
                                            SwStInputDetail swStInputDetail, String storage) {
        //设置票种
        swStStockDayCheckDetail.setTicketType(swStInputDetail.getTicketType());
        //车票名称
        swStStockDayCheckDetail.setTicketName(swStInputDetail.getTicketName());
        //车票次数
        swStStockDayCheckDetail.setTicketTimes(swStInputDetail.getTicketTimes());
        //车票金额
        swStStockDayCheckDetail.setTicketPrice(swStInputDetail.getTicketPrice());
        //出入库类型
        swStStockDayCheckDetail.setStorageType(storage);
        //设置库存分区
        swStStockDayCheckDetail.setStockArea(swStInputDetail.getStockArea());
        //todo 反查入库类型
        String inGoingTypeName = stStockDayCheckDetailMapper.getInGoningType(swStInputDetail.getInGoingType());
        swStStockDayCheckDetail.setOutInGoingType(inGoingTypeName);
        //入库时间
        swStStockDayCheckDetail.setOutInGoingTime(swStInputDetail.getInGoingTime());
        //车票有效期
        swStStockDayCheckDetail.setActiveTime(swStInputDetail.getActiveTime());
        //车票最晚启动日期
        swStStockDayCheckDetail.setLatestStartTime(swStInputDetail.getLatestStartTime());
        //库管员1工号
        swStStockDayCheckDetail.setKeeper1code(swStInputDetail.getKeeper1code());
        //库管员1
        swStStockDayCheckDetail.setKeeper1name(swStInputDetail.getKeeper1name());
        //库管员2工号
        swStStockDayCheckDetail.setKeeper2code(swStInputDetail.getKeeper2code());
        //库管员2
        swStStockDayCheckDetail.setKeeper2name(swStInputDetail.getKeeper2name());
        //起止号
        swStStockDayCheckDetail.setTicketNo(swStInputDetail.getTicketNo());
    }
    /**
     * 新的入库修改处理
     * @param swStInputDetail
     * @return
     */
    @Transactional
    public R updateInputDetailNew(SwStInputDetail swStInputDetail) {
        String errorMessage = "更新之后会存在结存数量小于当前车票数量，不允许修改！";
        try {
            //更新之前的数据
            SwStInputDetail oldData = super.getById(swStInputDetail.getId());
            //根据id获取相对应的结存数据
            SwStStockDayCheckDetail stockDayCheckDetail = sdcd.getById(swStInputDetail.getStockdayid());
            //更新入库数据
            super.updateById(swStInputDetail);
            //车票名称、库区、数量不变的情况下，直接更新车票金额和车票次数
            if(Objects.equals(swStInputDetail.getTicketName(),oldData.getTicketName()) &&
                    Objects.equals(swStInputDetail.getStockArea(),oldData.getStockArea()) &&
                    swStInputDetail.getTicketNumber().equals(oldData.getTicketNumber())){

                SwStStockDayCheckDetail swStStockDayCheckDetail = new SwStStockDayCheckDetail();
                swStStockDayCheckDetail.setTicketPrice(swStInputDetail.getTicketPrice());
                swStStockDayCheckDetail.setTicketTimes(swStInputDetail.getTicketTimes());
                swStStockDayCheckDetail.setId(stockDayCheckDetail.getId());
                return R.ok(sdcd.updateById(swStStockDayCheckDetail));
            }

            //查询大于此ID的所有数据,结存数量统一处理
            List<SwStStockDayCheckDetail> list =
                    sdcd.list(Wrappers.<SwStStockDayCheckDetail>lambdaQuery()
                            .eq(SwStStockDayCheckDetail::getTicketName,oldData.getTicketName())
                            .eq(SwStStockDayCheckDetail::getStockArea,oldData.getStockArea())
                            .gt(SwStStockDayCheckDetail::getId,stockDayCheckDetail.getId()));
            //车票和库区未变动：
            if(Objects.equals(swStInputDetail.getTicketName(),oldData.getTicketName()) && Objects.equals(swStInputDetail.getStockArea(),oldData.getStockArea()) ){
                if(oldData.getTicketNumber()!=null){
                    //先找到要修改的数据进行修改
                    SwStStockDayCheckDetail swStStockDayCheckDetail = new SwStStockDayCheckDetail();
                    //新数量-旧数量
                    int diff = swStInputDetail.getTicketNumber() - oldData.getTicketNumber();
                    //去掉限制，结存可以为负数
                    //if((stockDayCheckDetail.getSettleNumber()+diff)<0){
                    //    throw  new Exception(errorMessage);
                    //}
                    swStStockDayCheckDetail.setStorageNumber(swStInputDetail.getTicketNumber());
                    //入库加
                    swStStockDayCheckDetail.setSettleNumber(stockDayCheckDetail.getSettleNumber()+diff);
                    swStStockDayCheckDetail.setId(stockDayCheckDetail.getId());

                    if(CollectionUtil.isNotEmpty(list)){
                        for (SwStStockDayCheckDetail stStockDayCheckDetail : list) {
                            //去掉限制，结存可以为负数
                            //if((stStockDayCheckDetail.getSettleNumber()+diff)<0){
                            //    throw  new Exception(errorMessage);
                            //}
                            stStockDayCheckDetail.setSettleNumber(stStockDayCheckDetail.getSettleNumber()+diff);
                        }
                    }
                    list.add(swStStockDayCheckDetail);
                    sdcd.updateBatchById(list);
                }
            }
            //车票和库区有变动：删除匹配的数据，
            else {
                if(oldData.getTicketNumber()!=null){
                    int diff = oldData.getTicketNumber();
                    //修改时多入库，就直接减
                    if(CollectionUtil.isNotEmpty(list)){
                        for (SwStStockDayCheckDetail stStockDayCheckDetail : list) {
                            //去掉限制，结存可以为负数
                            //if((stStockDayCheckDetail.getSettleNumber()-diff)<0){
                            //    throw  new Exception(errorMessage);
                            //}
                            stStockDayCheckDetail.setSettleNumber(stStockDayCheckDetail.getSettleNumber()-diff);
                        }
                        sdcd.updateBatchById(list);
                    }
                    //有变动，删除结存表数据
                    SwStStockDayCheckDetail swStStockDayCheckDetailOld = new SwStStockDayCheckDetail();
                    swStStockDayCheckDetailOld.setId(swStInputDetail.getStockdayid());
                    sdcd.removeById(swStStockDayCheckDetailOld);

                    //根据车票名称和库区，找到最大的id号对应的结存数量
                    int settleNum = sdcd.getNewSettleNum(swStInputDetail.getTicketName(), swStInputDetail.getStockArea());
                    SwStStockDayCheckDetail swStStockDayCheckDetail = new SwStStockDayCheckDetail();
                    //重新新增一条变动后的数据
                    String inputOrOutPutstorage = "入库";
                    //数量
                    swStStockDayCheckDetail.setStorageNumber(swStInputDetail.getTicketNumber());
                    //结存数量+入库数量 = 新的结存数量。
                    swStStockDayCheckDetail.setSettleNumber(settleNum + swStInputDetail.getTicketNumber());
                    //处理公共属性
                    setSwStStockDayCheckDetail(swStStockDayCheckDetail,swStInputDetail,inputOrOutPutstorage);
                    swStStockDayCheckDetail.setOutputOrInputStockid(swStInputDetail.getId());
                    swStStockDayCheckDetail.setOutputOrInputStockno(swStInputDetail.getInstockno());
                    sdcd.save(swStStockDayCheckDetail);
                    //新增之后需要同步更新入库表相对应的关联库存id
                    swStInputDetail.setStockdayid(swStStockDayCheckDetail.getId());
                    super.updateById(swStInputDetail);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            //设置手动回滚
            TransactionAspectSupport.currentTransactionStatus()
                    .setRollbackOnly();
            return R.failed(e.getMessage().equals(errorMessage) ? e.getMessage() : "系统错误请联系管理员！");
        }
        return R.ok();
    }
    /**
     * 车票入库操作和完善信息
     * @param stInputDetail
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdateDetail(SwStInputDetail stInputDetail) {
        boolean issuccuess = true;
        //首先更新库存账
        SwStStockDayCheckDetail swStStockDayCheckDetail = new SwStStockDayCheckDetail();
        try {
            //根据车票名称和库区，找到最大的id号对应的结存数量
            int settleNum = sdcd.getNewSettleNum(stInputDetail.getTicketName(), stInputDetail.getStockArea());
            String inputstorage = "入库";
            setSwStStockDayCheckDetail(swStStockDayCheckDetail,stInputDetail,inputstorage);
            //更新库存量
            swStStockDayCheckDetail.setStorageNumber(stInputDetail.getTicketNumber());
            //结存数量+入库数量 = 新的结存数量。
            swStStockDayCheckDetail.setSettleNumber(settleNum + stInputDetail.getTicketNumber());
            swStStockDayCheckDetail.setOutputOrInputStockid(stInputDetail.getId());
            swStStockDayCheckDetail.setOutputOrInputStockno(stInputDetail.getInstockno());
            if (!StringUtils.isEmpty(stInputDetail.getRemark())) {
                swStStockDayCheckDetail.setRemark(stInputDetail.getRemark());
            }
            issuccuess = sdcd.save(swStStockDayCheckDetail);

            if (!issuccuess) {
                issuccuess = false;
                throw new RuntimeException("库存更新异常！");
            }
            //设置关联库存id
            stInputDetail.setStockdayid(swStStockDayCheckDetail.getId());
//            stInputDetail.setStockArea(stInputDetail.getStockAreaTemorary());
            issuccuess = issuccuess && super.updateById(stInputDetail);
        } catch (Exception e) {
            log.error("", e);
            throw new RuntimeException(e);
        }
        return issuccuess ;
    }
    /**
     * 旧的入库修改
     * @param swStInputDetail
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateInputDetail(SwStInputDetail swStInputDetail) {
        //更新之前的数据
        SwStInputDetail oldData = super.getById(swStInputDetail.getId());
        //更新入库数据
        boolean issuccues = super.updateById(swStInputDetail);

        if(Objects.equals(swStInputDetail.getTicketName(),oldData.getTicketName()) && Objects.equals(swStInputDetail.getStockArea(),oldData.getStockArea()) ){
            SwStStockDayCheckDetail stockDayCheckDetail = sdcd.getById(swStInputDetail.getStockdayid());
            SwStStockDayCheckDetail swStStockDayCheckDetail = new SwStStockDayCheckDetail();
            if(oldData.getTicketNumber()!=null){
                int diff = swStInputDetail.getTicketNumber()-oldData.getTicketNumber();
                swStStockDayCheckDetail.setStorageNumber(swStInputDetail.getTicketNumber());
                swStStockDayCheckDetail.setSettleNumber(stockDayCheckDetail.getSettleNumber()+diff);
            }
            swStStockDayCheckDetail.setId(stockDayCheckDetail.getId());
            sdcd.updateById(swStStockDayCheckDetail);
            //更新结存最新的数据
            SwStStockDayCheckDetail stockDayCheckDetails = stStockDayCheckDetailMapper.getInStockNewest(swStInputDetail.getTicketName(), swStInputDetail.getStockArea());
            if(stockDayCheckDetails!=null){
                if(!Objects.equals(stockDayCheckDetail.getId(),stockDayCheckDetails.getId())){
                    SwStStockDayCheckDetail swStStockDayCheckDetails = new SwStStockDayCheckDetail();
                    if(oldData.getTicketNumber()!=null){
                        int diff = swStInputDetail.getTicketNumber()-oldData.getTicketNumber();
                        swStStockDayCheckDetails.setSettleNumber(stockDayCheckDetails.getSettleNumber()+diff);
                    }
                    swStStockDayCheckDetails.setId(stockDayCheckDetails.getId());
                    sdcd.updateById(swStStockDayCheckDetails);
                }
            }
        }else{
            //如果改变车票名称或者票区时更新结存最新的数据
            //更新车票名称或者票区修改后对应的最新的数据
            SwStStockDayCheckDetail stockDayCheckDetails = stStockDayCheckDetailMapper.getInStockNewest(swStInputDetail.getTicketName(), swStInputDetail.getStockArea());
            if(stockDayCheckDetails!=null){
                SwStStockDayCheckDetail swStStockDayCheckDetails = new SwStStockDayCheckDetail();
                swStStockDayCheckDetails.setSettleNumber(stockDayCheckDetails.getSettleNumber()+swStInputDetail.getTicketNumber());
                swStStockDayCheckDetails.setId(stockDayCheckDetails.getId());
                sdcd.updateById(swStStockDayCheckDetails);
            }
            //删除车票名称或者票区修改前的旧的数据
            SwStStockDayCheckDetail swStStockDayCheckDetail = sdcd.getById(oldData.getStockdayid());
            swStStockDayCheckDetail.setTicketType(swStInputDetail.getTicketType());
            swStStockDayCheckDetail.setTicketName(swStInputDetail.getTicketName());
            swStStockDayCheckDetail.setTicketTimes(swStInputDetail.getTicketTimes());
            swStStockDayCheckDetail.setTicketPrice(swStInputDetail.getTicketPrice());
            swStStockDayCheckDetail.setStockArea(swStInputDetail.getStockArea());
            swStStockDayCheckDetail.setStorageNumber(swStInputDetail.getTicketNumber());
            int diff = swStInputDetail.getTicketNumber()-oldData.getTicketNumber();
            swStStockDayCheckDetail.setSettleNumber(swStStockDayCheckDetail.getSettleNumber()+diff);
            sdcd.updateById(swStStockDayCheckDetail);
            //如果改变车票名称或者票区时更新结存旧的数据
            SwStStockDayCheckDetail stockDayCheckDetail = stStockDayCheckDetailMapper.getInStockNewest(oldData.getTicketName(), oldData.getStockArea());
            if(stockDayCheckDetail!=null){
                SwStStockDayCheckDetail swStStockDayCheckDetails1 = new SwStStockDayCheckDetail();
                swStStockDayCheckDetails1.setSettleNumber(stockDayCheckDetail.getSettleNumber()-swStInputDetail.getTicketNumber());
                swStStockDayCheckDetails1.setId(stockDayCheckDetail.getId());
                sdcd.updateById(swStStockDayCheckDetails1);
            }
        }
        return issuccues;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(SwStInputDetail swStInputDetail) {
        SwStStockDayCheckDetail swStStockDayCheckDetail = sdcd.getById(swStInputDetail.getStockdayid());
        swStStockDayCheckDetail.setStorageNumber(swStInputDetail.getTicketNumber());
        if(!StringUtils.isEmpty(swStStockDayCheckDetail.getRemark())) {
            swStStockDayCheckDetail.setRemark(swStInputDetail.getRemark());
        }
        //首先更新库存
        if (!sdcd.saveOrUpdate(swStStockDayCheckDetail)) {
            throw new RuntimeException("更新库存异常!");
        }
        //更新入库数据
        return super.updateById(swStInputDetail);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeById(Serializable id) {
        //级联删除库存
        SwStInputDetail swStInputDetail = super.getById(id);
        long stockdayid = swStInputDetail.getStockdayid();
        if (!sdcd.removeById(stockdayid)) {
            throw new RuntimeException("更新库存异常!");
        }
        return super.removeById(id);
    }

    private int getSettleNum(SwStInputDetail swStInputDetail) {
        int settleNum = 0;
        int outStorageNum = sdcd.getOutStorgeNum(swStInputDetail.getTicketType(), swStInputDetail.getStockArea());
        int inStorageNum = sdcd.getInStorgeNum(swStInputDetail.getTicketType(), swStInputDetail.getStockArea());
        if (outStorageNum == 0 && inStorageNum == 0) {
            settleNum = 0;
        } else if (outStorageNum == 0 && inStorageNum != 0) {
            settleNum = inStorageNum;
        } else {
            //统计最新库存量 如果尚未尚未出库过，则库存为入库数
            settleNum = sdcd.getSettleNum(swStInputDetail.getTicketType(), swStInputDetail.getStockArea());
        }
        return settleNum;
    }

    /**
     * 导出通过ids导出文件
     *
     * @param dataList 导出数据ids
     * @param response
     */
    public void exportByIds(List<SwStInputDetailExcelDvo> dataList, HttpServletResponse response) {
        InputStream excelTemplateIs = null;
        if (CollectionUtil.isNotEmpty(dataList)) {
            try {
                response.setContentType("application/vnd.ms-excel");
                response.setCharacterEncoding("utf-8");
                final String fileName = URLEncoder.encode("车票入库", "UTF-8");
                response.setHeader("Content-disposition", "attachment;filename=" + fileName + System.currentTimeMillis() + ".xlsx");

                String[] titleStr = new String[]{"单号", "入库原因", "票种", "车票名称", "车票次数", "车票金额(票价)", "张数", "起号/止号", "车票有效期", "存放区域", "备注"};

                excelTemplateIs = this.getClass().getResourceAsStream("/static/excel/template/SwStInputDetailExcelDvo.xlsx");

                ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).registerConverter(new LocalDateTimeConverter()).registerConverter(new LocalDateConverter()).withTemplate(excelTemplateIs).build();
                WriteSheet writeSheet = EasyExcel.writerSheet("sheet1").build();
                FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
                excelWriter.fill(dataList, fillConfig, writeSheet);

                Map<String, Object> map = new HashMap<>();
                map.put("currMonth", DateUtils.format(new Date(), "yyyy年MM月dd日"));
                excelWriter.fill(map, writeSheet);
                excelWriter.finish();

            } catch (Exception e) {
                e.printStackTrace();
                log.error("车票入库数据错误");
            } finally {
                if (excelTemplateIs != null) {
                    try {
                        excelTemplateIs.close();
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                    }

                }
            }
        }

    }

    /**
     * 导出所有车票入库信息
     *
     * @param swInputExportExcelDTO
     * @param response
     */
    public void exportAll(SwInputExportExcelDTO swInputExportExcelDTO, HttpServletResponse response) {
        List<SwStInputDetailExcelDvo> dataList = swInputExportExcelDTO.getSwStInputDetailExcelBean();
        InputStream excelTemplateIs = null;
        if (CollectionUtil.isNotEmpty(dataList)) {
            Map<Integer,SwPmTicketAreaDvo> swPmTicketAreaDvoMap = null;
            Map<String,SwPmTicketCardTypeParamDvo> swPmTicketCardTypeParamDvoMap = null;
            Map<String,SwPmTicketCardTypeDvo> swPmTicketCardTypeDvoMap = null;
            Map<String,SysDictItemDTO> sysDictItemDTOMap = null;
            //查询票区名称字典 - 库区分区
            List<SwPmTicketAreaDvo> swPmTicketAreaDvo = (List<SwPmTicketAreaDvo>) subwaySupportService.getAreaDict().getData();
            if (CollectionUtil.isNotEmpty(swPmTicketAreaDvo)){
                swPmTicketAreaDvo = JSONObject.parseArray(JSONObject.toJSONString(swPmTicketAreaDvo),SwPmTicketAreaDvo.class);
                swPmTicketAreaDvoMap = swPmTicketAreaDvo.stream().collect(Collectors.toMap(SwPmTicketAreaDvo::getId, Function.identity(), (bean1, bean2) -> bean1));
            }
            //车票名称
            List<SwPmTicketCardTypeParamDvo> swPmTicketCardTypeParamDvos = (List<SwPmTicketCardTypeParamDvo>) subwaySupportService.getParamByMain().getData();
            if (CollectionUtil.isNotEmpty(swPmTicketCardTypeParamDvos)){
                swPmTicketCardTypeParamDvos = JSONObject.parseArray(JSONObject.toJSONString(swPmTicketCardTypeParamDvos),SwPmTicketCardTypeParamDvo.class);
                swPmTicketCardTypeParamDvoMap = swPmTicketCardTypeParamDvos.stream().collect(Collectors.toMap(SwPmTicketCardTypeParamDvo::getSubEnName, Function.identity(), (bean1, bean2) -> bean1));
            }
            //票种
            List<SwPmTicketCardTypeDvo> swPmTicketCardTypeDvos = (List<SwPmTicketCardTypeDvo>)subwaySupportService.getCardTypeDict().getData();
            if (CollectionUtil.isNotEmpty(swPmTicketCardTypeDvos)){
                swPmTicketCardTypeDvos = JSONObject.parseArray(JSONObject.toJSONString(swPmTicketCardTypeDvos),SwPmTicketCardTypeDvo.class);
                swPmTicketCardTypeDvoMap = swPmTicketCardTypeDvos.stream().collect(Collectors.toMap(SwPmTicketCardTypeDvo::getMainEnName, Function.identity(), (bean1, bean2) -> bean1));
            }
            //入库类型
            List<SysDictItemDTO> sysDictItemDTOS = swInputExportExcelDTO.getSysDictItemBean();
            if (CollectionUtil.isNotEmpty(sysDictItemDTOS)){
                sysDictItemDTOMap = sysDictItemDTOS.stream().collect(Collectors.toMap(SysDictItemDTO::getValue, Function.identity(), (bean1, bean2) -> bean1));
            }
            for (SwStInputDetailExcelDvo swStInputDetailExcelDvo : dataList) {
                if (CollectionUtil.isNotEmpty(swPmTicketAreaDvoMap) && swPmTicketAreaDvoMap.containsKey(Integer.valueOf(swStInputDetailExcelDvo.getStockArea()))){
                    swStInputDetailExcelDvo.setStockArea(swPmTicketAreaDvoMap.get(Integer.valueOf(swStInputDetailExcelDvo.getStockArea())).getTicketAreaName());
                }
                if (CollectionUtil.isNotEmpty(swPmTicketCardTypeParamDvoMap) && swPmTicketCardTypeParamDvoMap.containsKey(swStInputDetailExcelDvo.getTicketName())){
                    swStInputDetailExcelDvo.setTicketName(swPmTicketCardTypeParamDvoMap.get(swStInputDetailExcelDvo.getTicketName()).getSubName());
                }
                if (CollectionUtil.isNotEmpty(swPmTicketCardTypeDvoMap) && swPmTicketCardTypeDvoMap.containsKey(swStInputDetailExcelDvo.getTicketType())){
                    swStInputDetailExcelDvo.setTicketType(swPmTicketCardTypeDvoMap.get(swStInputDetailExcelDvo.getTicketType()).getMainName());
                }
                if (CollectionUtil.isNotEmpty(sysDictItemDTOMap) && sysDictItemDTOMap.containsKey(swStInputDetailExcelDvo.getInGoingType())){
                    swStInputDetailExcelDvo.setInGoingType(sysDictItemDTOMap.get(swStInputDetailExcelDvo.getInGoingType()).getLabel());
                }
            }
            try {
                response.setContentType("application/vnd.ms-excel");
                response.setCharacterEncoding("utf-8");
                final String fileName = URLEncoder.encode("车票入库", "UTF-8");
                response.setHeader("Content-disposition", "attachment;filename=" + fileName + System.currentTimeMillis() + ".xlsx");

                String[] titleStr = new String[]{"单号", "入库原因", "票种", "车票名称", "车票次数", "车票金额(票价)", "张数", "起号/止号", "车票有效期", "存放区域", "备注"};

                excelTemplateIs = this.getClass().getResourceAsStream("/static/excel/template/SwStInputDetailExcelDvo.xlsx");

                ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).registerConverter(new LocalDateTimeConverter()).registerConverter(new LocalDateConverter()).withTemplate(excelTemplateIs).build();
                WriteSheet writeSheet = EasyExcel.writerSheet("sheet1").build();
                FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
                excelWriter.fill(dataList, fillConfig, writeSheet);

                Map<String, Object> map = new HashMap<>();
                map.put("currMonth", DateUtils.format(new Date(), "yyyy年MM月dd日"));
                excelWriter.fill(map, writeSheet);
                excelWriter.finish();

            } catch (Exception e) {
                e.printStackTrace();
                log.error("车票入库数据错误");
            } finally {
                if (excelTemplateIs != null) {
                    try {
                        excelTemplateIs.close();
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                    }

                }
            }
        }

    }

    private List<List<String>> getExportHead(String[] titleStr) {
        List<List<String>> resultList = new ArrayList<>();
        List<String> titles = Arrays.asList(titleStr);
        String nowTime = DateUtil.format(new Date(), "yyyy年MM月dd日");
        resultList.add(Lists.newArrayList("车票入库单"));
        resultList.add(Lists.newArrayList("XDY/BB-PW-PWS-101", "", nowTime));
        resultList.add(titles);
        return resultList;
    }

}
